/**
 * @description 对 localStorage 进行加密缓存
 * @author darcrand
 */

// 加密次数
const ENCODE_TIMES = 3

function checkNamespace(namespace: string): void {
  if (namespace.trim().length === 0) {
    throw new Error('storage 命名空间不能为空')
  }
}

// 将对象转化成加密的字符串
function encode(data: Record<string, unknown>): string {
  let res = JSON.stringify(data)
  for (let i = 0; i < ENCODE_TIMES; i++) {
    res = window.btoa(res)
  }
  return res
}

// 将加密字符串还原为对象
function decode(encodeStr?: string | null): Record<string, unknown> {
  if (!encodeStr) {
    return {}
  }

  let strSource = encodeStr || ''
  for (let i = 0; i < ENCODE_TIMES; i++) {
    strSource = window.atob(strSource)
  }

  try {
    return JSON.parse(strSource)
  } catch (err) {
    return {}
  }
}

const storage = {
  setItem(namespace: string, state: Record<string, unknown>): void {
    checkNamespace(namespace)
    window.localStorage.setItem(namespace, encode(state))
  },

  getItem(namespace: string): Record<string, unknown> {
    checkNamespace(namespace)
    const str = window.localStorage.getItem(namespace)
    return decode(str)
  },

  removeItem(namespace: string) {
    checkNamespace(namespace)
    window.localStorage.removeItem(namespace)
  },

  clear() {
    window.localStorage.clear()
  },
}

export default storage
